package com.tcoiss.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcoiss.app.domain.*;
import com.tcoiss.app.mapper.GaodeDzMapper;
import com.tcoiss.app.service.IAdminDivisionService;
import com.tcoiss.app.service.IGaodeDzService;
import com.tcoiss.app.service.IGdAdminDivisionService;
import com.tcoiss.app.service.ITrackServiceService;
import com.tcoiss.common.core.enums.ErroEnums;
import com.tcoiss.common.core.exception.CustomException;
import com.tcoiss.common.core.utils.DateUtils;
import com.tcoiss.common.component.api.model.AddressVo;
import com.tcoiss.common.component.service.ApiHelperService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 高德编码对照表Service业务层处理
 *
 * @author zw
 * @date 2021-08-22
 */
@Service
public class GaodeDzServiceImpl extends ServiceImpl<GaodeDzMapper, GaodeDz> implements IGaodeDzService {

    @Autowired
    private ITrackServiceService iTrackServiceService;

    @Autowired
    private ApiHelperService apiHelperService;

    @Autowired
    private IAdminDivisionService aDivisionService;

    @Autowired
    private IGdAdminDivisionService iGdAdminDivisionService;

    @Override
    public List<GaodeDz> queryList(GaodeDz gaodeDz) {
        LambdaQueryWrapper<GaodeDz> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(gaodeDz.getLocalCode())) {
            lqw.eq(GaodeDz::getLocalCode, gaodeDz.getLocalCode());
        }
        if (StringUtils.isNotBlank(gaodeDz.getLocalName())) {
            lqw.like(GaodeDz::getLocalName, gaodeDz.getLocalName());
        }
        if (StringUtils.isNotBlank(gaodeDz.getGaodeCode())) {
            lqw.eq(GaodeDz::getGaodeCode, gaodeDz.getGaodeCode());
        }
        if (StringUtils.isNotBlank(gaodeDz.getGaodeName())) {
            lqw.like(GaodeDz::getGaodeName, gaodeDz.getGaodeName());
        }
        if (StringUtils.isNotBlank(gaodeDz.getLastFullName())) {
            lqw.like(GaodeDz::getLastFullName, gaodeDz.getLastFullName());
        }

        if (StringUtils.isNotBlank(gaodeDz.getStatus())) {
            if ("NQ".equals(gaodeDz.getStatus())) {
                lqw.ne(GaodeDz::getStatus, "0");
            } else {
                lqw.eq(GaodeDz::getStatus, gaodeDz.getStatus());
            }
        }
        // 判断是否存在时间值,如不存在则搜索当天
        if (gaodeDz.getCreateTime() != null) {
            lqw.ge(GaodeDz::getCreateTime, gaodeDz.getCreateTime());
            lqw.lt(GaodeDz::getCreateTime, DateUtils.dateTime(DateUtils.YYYY_MM_DD, DateUtils.getBeginDayOfTomorrow(DateUtils.YYYY_MM_DD)));
        } else {
            lqw.ge(GaodeDz::getCreateTime, DateUtils.dateTime(DateUtils.YYYY_MM_DD, DateUtils.getDate()));
        }
        return this.list(lqw);
    }

    /**
     * 用数据库查询高德编码进行对照
     *
     * @return
     */
    @Override
    public boolean dbQueryApi() {
        // 查询数据库数据不等于正常的
        List<GaodeDz> localCodeList = this.queryList(new GaodeDz().setStatus("NQ"));
        int index = 0;
        StringBuilder addressNames = new StringBuilder();
        List<GaodeDz> localList = new ArrayList<>();
        for (int i = 1; i <= localCodeList.size(); i++) {
            GaodeDz dz = localCodeList.get(index++);
            // 排除本地未拥有的数据
            if (!dz.getStatus().equals("3")) {
                localList.add(dz);
                String fullName = dz.getFullName();
                fullName = fullName.replaceAll("_", "");
                addressNames.append(fullName).append("|");
                if (localCodeList.size() == i || i % 10 == 0) {
                    // 拼接十条数据
                    addressNames.delete(addressNames.length() - 1, addressNames.length());
                    AddressVo addressVo = new AddressVo();
                    addressVo.setAddress(addressNames.toString());
                    addressNames = new StringBuilder();
                    // 将数据进行地理编码查询
                    List<AddressVo> adList = getLocation(addressVo);
                    // 将坐标抽取出来做成List
                    List<String> coordsList = adList.stream().map(AddressVo::getAddress).collect(Collectors.toList());
                    StringBuilder location = new StringBuilder();
                    Map<String, Object> requestMap = new HashMap<>();
                    // 在根据查询出来的坐标,查询第四级
                    for (String coords : coordsList) {
                        location.append(coords).append("|");
                    }
                    try {
                        location.delete(location.length() - 1, location.length());
                        requestMap.put("location", URLEncoder.encode(location.toString(), "utf-8"));
                        requestMap.put("key", iTrackServiceService.getDefaultKey().getGaodeKey());
                        requestMap.put("batch", "true");
                    } catch (UnsupportedEncodingException e) {
                        throw new CustomException(ErroEnums.SYSERRO.getCode(), new Object[]{location}
                                , "系统异常");
                    }
                    // 根据坐标查询第四级
                    Map<String, Object> resultMap = apiHelperService.executeApi("getAddressByLocation", requestMap);
                    if (resultMap == null) {
                        throw new CustomException(ErroEnums.APIERRO.getCode(), new Object[]{"getAddressByLocation"}
                                ,ErroEnums.APIERRO.getInfo() + "获取地址坐标请求连接异常");
                    } else {
                        //成功
                        if (Integer.parseInt(resultMap.get("status").toString()) == 1) {
                            //获取乡镇代码
                            List<ExcelVo> excelVos = new ArrayList<>();
                            List<Map<String, Object>> regeocodes = (List<Map<String, Object>>) resultMap.get("regeocodes");
                            for (int j = 0; j < regeocodes.size(); j++) {
                                Map<String, Object> addressComponent = regeocodes.get(j);
                                Map<String, Object> townMap = (Map<String, Object>) addressComponent.get("addressComponent");
                                ExcelVo townExcelVo = new ExcelVo();
                                if (townMap.get("towncode") instanceof String) {
                                    townExcelVo.setNumber((String) townMap.get("towncode"));
                                }
                                townExcelVo.setLastNo((String) townMap.get("adcode"));
                                if (townMap.get("township") instanceof String) {
                                    townExcelVo.setName(townMap.get("township").toString());
                                }
                                townExcelVo.setType("4");
                                excelVos.add(townExcelVo);
                            }
                            List<GaodeDz> errorList = checkDataDBQueryApi(excelVos, localList);
                            if (!errorList.isEmpty()) {
                                saveBatch(errorList.stream().distinct().collect(Collectors.toList()));
                            }
                            localList.clear();
                        }
                    }
                }
            }
        }
        return true;
    }

    @Override
    public boolean handleDZ() {
        //清空历史对照数据
        LambdaQueryWrapper<GaodeDz> lqw = Wrappers.lambdaQuery();
        this.remove(lqw );
        //获取苍穹list集合
        AdminDivision queryAdminDivision = new AdminDivision().setFullName("jxs");
        queryAdminDivision.setAdministrativeLevelsId(4L);
        List<AdminDivision> adminDivisions = aDivisionService.getList(queryAdminDivision);
        List<GdAdminDivision> gdlist = new ArrayList<>();
        List<GaodeDz> gaodeDzs = new ArrayList<>();
        //根据本地四级行政区划全名称查询高德行政区划
        for(AdminDivision adminDivision:adminDivisions){
            String fullname = adminDivision.getFullName();
            List<GdAdminDivision> gdAdminDivisions = iGdAdminDivisionService.getList(new GdAdminDivision().setFullName(fullname));
            if(gdAdminDivisions!=null&&gdAdminDivisions.size()>0){//匹配成功则非异常数据
                //标记本次对照成功的数据
                adminDivision.setEnable("2");
                gdAdminDivisions.get(0).setEnable("2");
                gdlist.add(gdAdminDivisions.get(0));
            }else{//通过全名称逆地理和地理接口查询新的名称,如果查询不到则完全比配不到 生成对照信息
                //Map<String,Object> town = queryTownByApi(fullname);
                GaodeDz gaodeDz = new GaodeDz();
                String lastFullName = aDivisionService.getLastFullName(adminDivision.getParent());
                /*if(town!=null){//名称变化的
                    gaodeDz.setLocalName(adminDivision.getName());
                    gaodeDz.setGaodeName(town.get("township").toString());
                    gaodeDz.setStatus("1");
                    //获取上级全名称
                    gaodeDz.setFullName(adminDivision.getFullName());
                    gaodeDz.setLastFullName(lastFullName);
                    gaodeDz.setCreateTime(new Date());
                }else{// 找不到变化后名称*/
                    gaodeDz.setLocalName(adminDivision.getName());
                    gaodeDz.setGaodeName("");
                    gaodeDz.setStatus("2");
                    //获取上级全名称
                    gaodeDz.setFullName(adminDivision.getFullName());
                    gaodeDz.setLastFullName(lastFullName);
                    gaodeDz.setCreateTime(new Date());
                //}
                gaodeDzs.add(gaodeDz);
            }
        }
        if(iGdAdminDivisionService.updateBatchById(gdlist)){
            //二次对照通过高德查询苍穹 对上次异常数据再次对照
            GdAdminDivision queryGdAdminDivision = new GdAdminDivision().setAdministrativeLevelsId(4L);
            queryGdAdminDivision.setEnable("2");
            List<GdAdminDivision> gdAdminDivisions = iGdAdminDivisionService.getList(queryGdAdminDivision);
            for(GdAdminDivision gdAdminDivision:gdAdminDivisions){
                String fullname = gdAdminDivision.getFullName();
                List<AdminDivision> adminDivisions1 = aDivisionService.getList(new AdminDivision().setFullName(fullname));
                String lastFullName = iGdAdminDivisionService.getLastFullName(gdAdminDivision.getParent());
                GaodeDz gaodeDz = new GaodeDz();
                if(adminDivisions1!=null&&adminDivisions1.size()>0) {//匹配成功则非异常数据
                    gaodeDz.setLocalName(adminDivisions1.get(0).getName());
                    gaodeDz.setGaodeName(gdAdminDivision.getName());
                    gaodeDz.setStatus("1");
                    gaodeDz.setFullName(gdAdminDivision.getFullName());
                    //获取上级全名称
                    gaodeDz.setLastFullName(lastFullName);
                    gaodeDz.setCreateTime(new Date());
                }else{//高德存在本地不存在,生成对照信息  排除已经对照出来的异常信息
                    /*GaodeDz gaodeDz1 = new GaodeDz().setGaodeName(gdAdminDivision.getName());
                    List<GaodeDz> gaodeDzList = this.queryList(gaodeDz1);
                    if(gaodeDzList==null||gaodeDzList.size()==0){// 找不到苍穹*/
                    gaodeDz.setLocalName("");
                    gaodeDz.setGaodeName(gdAdminDivision.getName());
                    gaodeDz.setStatus("3");
                    gaodeDz.setFullName(gdAdminDivision.getFullName());
                    //获取上级全名称
                    gaodeDz.setLastFullName(lastFullName);
                    gaodeDz.setCreateTime(new Date());
                    //}

                }
                gaodeDzs.add(gaodeDz);
            }
        }else{
            return true;
        }
        LambdaQueryWrapper<GdAdminDivision> lqw2 = Wrappers.lambdaQuery();
        lqw2.eq(GdAdminDivision::getEnable,"2");
        iGdAdminDivisionService.update(new GdAdminDivision().setEnable("1"),lqw2);
        return this.saveBatch(gaodeDzs);
    }

    public Map<String,Object> queryTownByApi(String fullName) {
        fullName = fullName.replaceAll("_", "");
        AddressVo addressVo = new AddressVo();
        addressVo.setAddress(fullName);
        // 将数据进行地理编码查询
        List<AddressVo> adList = getLocation(addressVo);
        // 将坐标抽取出来做成List
        List<String> coordsList = adList.stream().map(AddressVo::getAddress).collect(Collectors.toList());
        String location = coordsList.get(0);
        Map<String, Object> requestMap = new HashMap<>();
        try {
            requestMap.put("location", URLEncoder.encode(location.toString(), "utf-8"));
            requestMap.put("key", iTrackServiceService.getDefaultKey().getGaodeKey());
            requestMap.put("batch", "true");
        } catch (UnsupportedEncodingException e) {
            throw new CustomException(ErroEnums.SYSERRO.getCode(), new Object[]{location}, "系统异常");
        }
        // 根据坐标查询第四级
        Map<String, Object> resultMap = apiHelperService.executeApi("getAddressByLocation", requestMap);
        if (resultMap == null) {
            throw new CustomException(ErroEnums.APIERRO.getCode(),new Object[]{"getAddressByLocation"},ErroEnums.APIERRO.getInfo() + "获取地址坐标请求连接异常");
        } else {
            //成功
            if (Integer.parseInt(resultMap.get("status").toString()) == 1) {
                //获取乡镇代码
                List<ExcelVo> excelVos = new ArrayList<>();
                List<Map<String, Object>> regeocodes = (List<Map<String, Object>>) resultMap.get("regeocodes");
                Map<String, Object> addressComponent = regeocodes.get(0);
                Map<String, Object> townMap = (Map<String, Object>) addressComponent.get("addressComponent");
                return townMap;

            }
        }
        return null;
    }


    /**
     * 数值比较
     *
     * @return
     */
    private List<GaodeDz> checkDataDBQueryApi(List<ExcelVo> gaode, List<GaodeDz> local) {
        List<GaodeDz> gaodeDzList = new ArrayList<>();
        if (gaode.size() != 10) {
            return gaodeDzList;
        }
        for (int i = 0; i < gaode.size(); i++) {
            ExcelVo gDz = gaode.get(i);
            GaodeDz lDz = local.get(i);
            lDz.setId(null);
            lDz.setGaodeName(gDz.getName());
            lDz.setGaodeCode(gDz.getNumber());
            if(StringUtils.isNotBlank(gDz.getNumber())){
                // 名称是否相同与编码是否相同
                if (gDz.getName().equals(lDz.getLocalName()) && gDz.getNumber().equals(lDz.getLocalCode())) {
                    lDz.setDetails("");
                    lDz.setStatus("0");
                    gaodeDzList.add(lDz);
                    continue;
                }
                // 检查名称相同，但编码不同
                if (gDz.getName().equals(lDz.getLocalName())) {
                    lDz.setDetails("名称相同，但编码不同。  本地名称" + lDz.getLocalName() + ",高德名称" + gDz.getName() + "," +
                            "高德更改编码为:" + gDz.getNumber() + "当前本地编码为:" + lDz.getLocalCode());
                    lDz.setStatus("1");
                    gaodeDzList.add(lDz);
                    continue;
                }
                // 检查编码相同,但名称不同
                if (gDz.getNumber().equals(lDz.getLocalCode())) {
                    lDz.setDetails("编码相同,但名称改变。 本地编码为:" + lDz.getLocalCode() + "的高德的名称发生改变," +
                            "当前本地编码上的乡镇为:" + gDz.getName() + ",的本地名称为:" + lDz.getLocalName() + ",仅供参考!");
                    lDz.setStatus("2");
                    gaodeDzList.add(lDz);
                    continue;
                }
                // 编码名称都不相同
                lDz.setDetails("编码名称都发生改变。 本地编码为:" + lDz.getLocalCode() + "的高德的名称发生改变," +
                        "当前本地编码上的乡镇为:" + gDz.getName() + ",的本地名称为:" + lDz.getLocalName() + ",仅供参考!");
                lDz.setStatus("2");
                gaodeDzList.add(lDz);
            }
        }
        return gaodeDzList;
    }

    /**
     * 同步对照表
     *
     * @return
     */
    @Override
    public boolean syncDzBill() {
        List<ExcelVo> gaodeCodeList = getTownCode();
        //List<ExcelVo> gaodeCodeList = redisService.getCacheList("gaode");
        List<AdminDivision> localCodeList = aDivisionService.getList(new AdminDivision().setFullName("jxs"));
        List<GaodeDz> gaodeDzList = new ArrayList<>();
        for (int i = 4; i < 5; i++) {
            String num = String.valueOf(i);
            List<ExcelVo> gaodeLevels = gaodeCodeList.stream()
                    .filter(gaode -> num.equals(gaode.getType())).collect(Collectors.toList());
            List<AdminDivision> localLevels = localCodeList.stream()
                    .filter(local -> num.equals(local.getAdministrativeLevelsId().toString())).collect(Collectors.toList());
            if (num.equals("1")) {
                for (ExcelVo ev : gaodeLevels) {
                    for (AdminDivision ad : localLevels) {
                        GaodeDz dz = new GaodeDz();
                        // 判断省级编码与名称是否相同
                        if (ev.getNumber().equals(ad.getNumber()) && ev.getName().equals(ad.getName())) {
                            dz.setStatus("0");
                        } else if (ev.getNumber().equals(ad.getNumber())) {
                            dz.setStatus("2");
                        } else if (ev.getName().equals(ad.getName())) {
                            ad.setStatus("1");
                        }
                        dz.setGaodeCode(ev.getNumber());
                        dz.setGaodeName(ev.getName());
                        dz.setLocalName(ad.getName());
                        dz.setLocalCode(ad.getNumber());
                        gaodeDzList.add(dz);
                    }
                }
            } else {
                gaodeDzList.addAll(checkData(gaodeLevels, localLevels));
            }
        }
        return saveBatch(gaodeDzList.stream().distinct().collect(Collectors.toList()));
    }

    /**
     * 检查数据
     */
    private List<GaodeDz> checkData(List<ExcelVo> gaodeLevels, List<AdminDivision> localLevels) {
        List<GaodeDz> gaodeDzList = new ArrayList<>();
        for (ExcelVo gCode : gaodeLevels) {
            GaodeDz dz = new GaodeDz();
            for (AdminDivision lCode : localLevels) {
                // 判断上级编码是否一致
                if (gCode.getLastNo().equals(lCode.getParent().toString())) {
                    // 判断高德编码是否为空但名称匹配
                    if (StringUtils.isBlank(gCode.getNumber())) {
                        if (gCode.getName().equals(lCode.getName())) {
                            dz.setGaodeCode(gCode.getNumber());
                            dz.setGaodeName(gCode.getName());
                            dz.setLocalName(lCode.getName());
                            dz.setLocalCode(lCode.getNumber());
                            dz.setFullName(lCode.getFullName());
                            dz.setDetails("高德编码为空,但名称相同," + "高德编码为:"
                                    + gCode.getNumber() + "苍穹编码为:" + lCode.getNumber() +
                                    "高德上级编码为:" + gCode.getLastNo() + "苍穹上级编码为:" + lCode.getParent());
                            dz.setStatus("5");
                            gaodeDzList.add(dz);
                            lCode.setSyncSign("0");
                            gCode.setSyncSign("0");
                            break;
                        }
                        continue;
                    }
                    // 编码相同名称相同
                    if (gCode.getNumber().equals(lCode.getNumber()) && gCode.getName().equals(lCode.getName())) {
                        dz.setGaodeCode(gCode.getNumber());
                        dz.setGaodeName(gCode.getName());
                        dz.setLocalName(lCode.getName());
                        dz.setLocalCode(lCode.getNumber());
                        dz.setFullName(lCode.getFullName());
                        dz.setStatus("0");
                        gaodeDzList.add(dz);
                        lCode.setSyncSign("0");
                        gCode.setSyncSign("0");
                        break;
                    }
                    // 编码相同但名称不同
                    if (gCode.getNumber().equals(lCode.getNumber()) && (!gCode.getName().equals(lCode.getName()))) {
                        dz.setGaodeCode(gCode.getNumber());
                        dz.setGaodeName(gCode.getName());
                        dz.setLocalName(lCode.getName());
                        dz.setLocalCode(lCode.getNumber());
                        dz.setFullName(lCode.getFullName());
                        dz.setDetails("高德与本地编码相同,但名称不同," + "高德名称为:" +
                                gCode.getName() + "苍穹名称为:" + lCode.getName() +
                                "高德上级编码为:" + gCode.getLastNo() + "苍穹上级编码为:" + lCode.getParent());
                        dz.setStatus("2");
                        gaodeDzList.add(dz);
                        lCode.setSyncSign("0");
                        gCode.setSyncSign("0");
                    }
                    // 编码不同但名称相同
                    if ((!gCode.getNumber().equals(lCode.getNumber())) && gCode.getName().equals(lCode.getName())) {
                        dz.setGaodeName(gCode.getName());
                        dz.setGaodeCode(gCode.getNumber());
                        dz.setLocalCode(lCode.getNumber());
                        dz.setLocalName(lCode.getName());
                        dz.setFullName(lCode.getFullName());
                        dz.setDetails("高德与本地编码不同,但名称相同," + "高德编码为:" +
                                gCode.getNumber() + "苍穹编码为:" + lCode.getNumber() +
                                "高德上级编码为:" + gCode.getLastNo() + "苍穹上级编码为:" + lCode.getParent());
                        dz.setStatus("1");
                        gaodeDzList.add(dz);
                        lCode.setSyncSign("0");
                        gCode.setSyncSign("0");
                        break;
                    }
                } else {
                    // 给暂未处理的同步标记赋值为1;
                    if (com.tcoiss.common.core.utils.StringUtils.isEmpty(lCode.getSyncSign())) {
                        lCode.setSyncSign("1");
                    }
                    if (com.tcoiss.common.core.utils.StringUtils.isEmpty(gCode.getSyncSign())) {
                        gCode.setSyncSign("1");
                    }
                }
            }
        }
        List<AdminDivision> localSyncSigns = localLevels.stream()
                .filter(local -> "1".equals(local.getSyncSign())).collect(Collectors.toList());
        for (AdminDivision localGaode : localSyncSigns) {
            GaodeDz dz = new GaodeDz();
            dz.setLocalCode(localGaode.getNumber());
            dz.setLocalName(localGaode.getName());
            dz.setStatus("4");
            dz.setFullName(localGaode.getFullName());
            dz.setDetails("高德已删除:" + localGaode.getName() +
                    "编码为:" + localGaode.getNumber() +
                    "上级编码为:" + localGaode.getParent());
            gaodeDzList.add(dz);
        }
        List<ExcelVo> gaodeSyncSigns = gaodeLevels.stream()
                .filter(gcode -> "1".equals(gcode.getSyncSign())).collect(Collectors.toList());
        for (ExcelVo gaode : gaodeSyncSigns) {
            GaodeDz dz = new GaodeDz();
            dz.setGaodeCode(gaode.getNumber());
            dz.setGaodeName(gaode.getName());
            dz.setStatus("3");
            dz.setDetails("本地未拥有:" + gaode.getName() +
                    "编码为:" + gaode.getNumber() +
                    "上级编码为:" + gaode.getLastNo());
            gaodeDzList.add(dz);
        }
        return gaodeDzList;
    }

    /**
     * 获取第四级以及上级List
     *
     * @return
     */
    @Override
    public List<ExcelVo> getTownCode() {
        Map<String, Object> map = new HashMap<>();
        List<ExcelVo> excelVos = new ArrayList<>();
        try {
            map.put("keywords", URLEncoder.encode("江西省", "utf-8"));
        } catch (UnsupportedEncodingException e) {
            throw new CustomException(ErroEnums.SYSERRO.getCode(), new Object[]{"江西省"}, "系统异常");
        }
        map.put("subdistrict", 3);
        map.put("extensions", "base");
        map.put("key", iTrackServiceService.getDefaultKey().getGaodeKey());
        // 请求行政区划获取第四级地址与名称
        Map<String, Object> resultMap = apiHelperService.executeApi("getDistrictInfo", map);
        if (resultMap == null) {
            throw new CustomException(ErroEnums.APIERRO.getCode(), new Object[]{"getDistrictInfo"},ErroEnums.APIERRO.getInfo() + "获取地址坐标请求连接异常");
        } else {
            //成功
            if (Integer.parseInt(resultMap.get("status").toString()) == 1) {
                // 获取江西省
                List<Map<String, Object>> province = (List<Map<String, Object>>) resultMap.get("districts");
                for (int i = 0; i < province.size(); i++) {
                    Map<String, Object> provinceCode = province.get(0);
                    ExcelVo provinceExcelVo = new ExcelVo();
                    provinceExcelVo.setNumber((String) provinceCode.get("adcode"));
                    provinceExcelVo.setName((String) province.get(i).get("name"));
                    provinceExcelVo.setType("1");
                    excelVos.add(provinceExcelVo);
                    // 获取所有市级
                    List<Map<String, Object>> city = (List<Map<String, Object>>) province.get(i).get("districts");
                    for (int j = 0; j < city.size(); j++) {
                        Map<String, Object> cityCode = city.get(j);
                        ExcelVo cityExcelVo = new ExcelVo();
                        cityExcelVo.setNumber((String) cityCode.get("citycode"));
                        cityExcelVo.setLastNo((String) province.get(0).get("adcode"));
                        cityExcelVo.setName((String) city.get(j).get("name"));
                        cityExcelVo.setType("2");
                        excelVos.add(cityExcelVo);
                        // 获取当前市的区县
                        List<Map<String, Object>> district = (List<Map<String, Object>>) city.get(j).get("districts");
                        for (int k = 0; k < district.size(); k++) {
                            Map<String, Object> districtCode = district.get(k);
                            ExcelVo districtExcelVo = new ExcelVo();
                            districtExcelVo.setNumber((String) districtCode.get("adcode"));
                            districtExcelVo.setLastNo(districtCode.get("citycode").toString());
                            districtExcelVo.setType("3");
                            String name = province.get(i).get("name") + (String) city.get(j).get("name") + district.get(k).get("name");
                            districtExcelVo.setName((String) district.get(k).get("name"));
                            excelVos.add(districtExcelVo);
                            // 获取当前区县的乡镇
                            List<Map<String, Object>> town = (List<Map<String, Object>>) district.get(k).get("districts");
                            List<ExcelVo> townList = getTownList(town, name, districtExcelVo.getNumber());
                            excelVos.addAll(townList);
                        }
                    }
                }
                //redisService.setCacheList("gaode", excelVos);
                return excelVos;
            }
        }
        return null;
    }



    /**
     * 获取乡镇编码list
     *
     * @param towns    该区域下的乡镇列表
     * @param townName 完整拼接的乡镇名称(江西省 + 市级 + 区县 + 乡镇)
     * @return
     */
    private List<ExcelVo> getTownList(List<Map<String, Object>> towns, String townName, String lastNumber) {
        List<ExcelVo> excelVos = new ArrayList<>();
        int count = 0;
        StringBuilder location = new StringBuilder();
        StringBuilder addressName = new StringBuilder();
        List<ExcelVo> excelNames = new ArrayList<>();
        // 每十个ExcelVo实体进行一次逆地理(坐标查询第四级)
        int index = 0;
        for (int i = 1; i <= towns.size(); i++) {
            Map<String, Object> townsCode = towns.get(index++);
            // 将乡镇名称用|分割开去请求getLocation() 获取坐标
            addressName.append(townName).append(townsCode.get("name")).append("|");
            ExcelVo excelVo = new ExcelVo();
            excelVo.setName((String) townsCode.get("name"));
            excelVo.setCenter((String) townsCode.get("center"));
            excelNames.add(excelVo);
            if (towns.size() == i || i % 10 == 0) {
                Map<String, Object> map = new HashMap<>();
                AddressVo addressVo = new AddressVo();
                addressName.delete(addressName.length() - 1, addressName.length());
                addressVo.setAddress(addressName.toString());
                List<AddressVo> avList = getLocation(addressVo);
                assert avList != null;
                // 将坐标抽取出来做成List
                List<String> coordsList = avList.stream().map(AddressVo::getAddress).collect(Collectors.toList());
                for (String coords : coordsList) {
                    location.append(coords).append("|");
                }
                if (location.length() > 0) {
                    location.delete(location.length() - 1, location.length());
                }
                try {
                    map.put("location", URLEncoder.encode(location.toString(), "utf-8"));
                    map.put("key", iTrackServiceService.getDefaultKey().getGaodeKey());
                    map.put("batch", "true");
                } catch (UnsupportedEncodingException e) {
                    throw new CustomException(ErroEnums.SYSERRO.getCode(), new Object[]{location}, "系统异常");
                }
                // 根据坐标查询第四级
                Map<String, Object> resultMap = apiHelperService.executeApi("getAddressByLocation", map);
                location.delete(0, location.length());
                addressName.delete(0, addressName.length());
                if (resultMap == null) {
                    throw new CustomException(ErroEnums.APIERRO.getCode(), new Object[]{"getAddressByLocation"},
                            ErroEnums.APIERRO.getInfo() + "获取地址坐标请求连接异常");
                } else {
                    //成功
                    if (Integer.parseInt(resultMap.get("status").toString()) == 1) {
                        //获取乡镇代码
                        List<Map<String, Object>> regeocodes = (List<Map<String, Object>>) resultMap.get("regeocodes");
                        for (int j = 0; j < regeocodes.size(); j++) {
                            Map<String, Object> addressComponent = regeocodes.get(j);
                            Map<String, Object> townMap = (Map<String, Object>) addressComponent.get("addressComponent");
                            ExcelVo townExcelVo = new ExcelVo();
                            if (townMap.get("towncode") instanceof String) {
                                townExcelVo.setNumber((String) townMap.get("towncode"));
                            }
                            townExcelVo.setLastNo(lastNumber);
                            if (townMap.get("township") instanceof String) {
                                if (townMap.get("township").toString().equals(excelNames.get(count).getName())) {
                                    townExcelVo.setName(excelNames.get(count++).getName());
                                } else {
                                    ExcelVo excelVo1 = getTownShipByCenter(excelNames.get(count).getCenter(), townName, excelNames.get(count++).getName(), lastNumber);
                                    townExcelVo.setName(excelVo1.getName());
                                    townExcelVo.setNumber(excelVo1.getNumber());
                                }
                            } else {
                                townExcelVo.setName(excelNames.get(count++).getName());
                            }
                            townExcelVo.setType("4");
                            excelVos.add(townExcelVo);
                        }
                    }
                }
            }
        }
        return excelVos;
    }

    /**
     * 根据名称获取坐标
     *
     * @param address
     * @return
     */
    private List<AddressVo> getLocation(AddressVo address) {
        Map<String, Object> map = new HashMap<>();
        List<AddressVo> avList = new ArrayList<>();
        try {
            map.put("address", URLEncoder.encode(address.getAddress(), "utf-8"));
        } catch (UnsupportedEncodingException e) {
            throw new CustomException(ErroEnums.SYSERRO.getCode(), new Object[]{address.getAddress()}, "系统异常");
        }
        map.put("key", iTrackServiceService.getDefaultKey().getGaodeKey());
        map.put("batch", "true");
        Map<String, Object> resultMap = apiHelperService.executeApi("geocode", map);
        if (resultMap == null) {
            throw new CustomException(ErroEnums.APIERRO.getCode(), new Object[]{"geocode"},
                    ErroEnums.APIERRO.getInfo() + "获取地址坐标请求连接异常");
        } else {
            //成功
            if (Integer.parseInt(resultMap.get("status").toString()) == 1) {
                //获取地址坐标数据
                List<Map<String, Object>> geocodes = (List<Map<String, Object>>) resultMap.get("geocodes");
                if (geocodes == null || geocodes.size() == 0) {
                    throw new CustomException(ErroEnums.APIERRO.getCode(), new Object[]{"解析节点为: geocode"},
                            ErroEnums.APIERRO.getInfo() + "无法解析地址信息");
                }
                for (int i = 0; i < geocodes.size(); i++) {
                    AddressVo av = new AddressVo();
                    Map<String, Object> geocode = geocodes.get(i);
                    String location = geocode.get("location").toString();
                    av.setAddress(location);
                    av.setDistrict(geocode.get("level").toString());
                    avList.add(av);
                }
                return avList;
            }
        }
        return null;
    }

    /**
     * 如乡镇名称不匹配则使用行政区域查询的Center来进行搜索
     *
     * @param center       行政区域查询的Center
     * @param districtName 当前搜索的乡镇上级区县名称
     * @param townName     当前搜索的乡镇名称
     * @return
     */
    private ExcelVo getTownShipByCenter(String center, String districtName, String townName, String lastNumber) {
        Map<String, Object> map = new HashMap<>();
        try {
            map.put("location", URLEncoder.encode(center, "utf-8"));
            map.put("key", iTrackServiceService.getDefaultKey().getGaodeKey());
            map.put("batch", "false");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Map<String, Object> resultMap = apiHelperService.executeApi("getAddressByLocation", map);
        if (resultMap == null) {
            throw new CustomException(ErroEnums.APIERRO.getCode(), new Object[]{"getAddressByLocation"},
                    ErroEnums.APIERRO.getInfo() + "获取地址坐标请求连接异常");
        } else {
            ExcelVo excelVo = new ExcelVo();
            //成功
            if (Integer.parseInt(resultMap.get("status").toString()) == 1) {
                Map<String, Object> regeocodes = (Map<String, Object>) resultMap.get("regeocode");
                Map<String, Object> townMap = (Map<String, Object>) regeocodes.get("addressComponent");
                if (townMap.get("township") instanceof String) {
                    if (townName.equals(townMap.get("township"))) {
                        excelVo.setNumber((String) townMap.get("towncode"));
                        excelVo.setLastNo(lastNumber);
                    }
                }
                excelVo.setName(townName);
                return excelVo;
            }
        }
        return null;
    }

}
